package message

import (
	"fmt"
	"time"
)

// Publisher 发布消息
func Publisher[T Message](t T) {
	ch := getMsgChan(t)
	ch <- t
}

// Listen 监听消息
func Listen[T Message](fun func(t T)) {
	var t T
	msgValid(t) // 校验消息合法
	arr, ok := msgHandlerMap[t.MessageType()]
	if !ok {
		//没有则初始化
		initChanAndHandlerArr(t)
		arr = msgHandlerMap[t.MessageType()]
	}
	arrHandArr := arr.([]func(t T))
	arrHandArr = append(arrHandArr, fun)
	msgHandlerMap[t.MessageType()] = arrHandArr //赋值回去
}

// Close 主动关闭入口， 例如项目启动这类一次性消息，启动稳定后就不再需要监听了
func Close[T Message](sleep time.Duration) {
	go func() {
		time.Sleep(sleep)
		var t T
		msgValid(t) // 校验消息合法
		ch, ok := msgChannelMap[t.MessageType()]
		if !ok {
			return
		}
		cha := ch.(chan T)
		close(cha)
	}()
}

func getMsgChan[T Message](t T) chan T {
	msgValid(t) // 校验消息合法
	ch, ok := msgChannelMap[t.MessageType()]
	if !ok {
		initChanAndHandlerArr(t)
		ch = msgChannelMap[t.MessageType()]
	}
	return ch.(chan T)
}

// 管道和方法数组成对初始化
func initChanAndHandlerArr[T Message](t T) {
	// 初始化管道
	ch := make(chan T, t.ChannelLent())
	msgChannelMap[t.MessageType()] = ch

	// 初始化方法数组
	handlerArr := make([]func(t T), 0)
	msgHandlerMap[t.MessageType()] = handlerArr

	//初始化监听
	go func() {
		for {
			item, ok := <-ch
			if !ok {
				//说明管道关闭 清理掉 不再引用
				fmt.Println("close chan ", item.MessageType())
				delete(msgChannelMap, item.MessageType())
				delete(msgHandlerMap, item.MessageType())
				break
			}
			a := msgHandlerMap[item.MessageType()]
			funcs := a.([]func(t T))
			for _, fun := range funcs {
				func() {
					defer func() {
						if r := recover(); r != nil {
							fmt.Println("Message channel Recovered  ", r)
						}
					}()
					fun(item)
				}()
			}
		}
	}()
}
